import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import junit.framework.TestCase;

import org.junit.Before;
import org.junit.Test;

public class UrlValidatorTestTeam extends TestCase {
	private static boolean setUpIsDone = false;

	public UrlValidatorTestTeam(String testName) {
		super(testName);
	}

	@Before
	protected void setUp() {
		setUpSchemes(coreSchemeNames, invalidSchemeNames);
		setUpAuthorities();
	}
	
	protected void setUpSchemes(ResultPair[]... schemeNameArrays) {
		/*
		 * Fill 'schemes' list with a variety of valid and invalid schemes
		 */
		for(ResultPair[] schemeNames : schemeNameArrays) {
			for(ResultPair scheme : schemeNames) {
				String item = scheme.item;
				Boolean isValid = scheme.valid;

				/* 
				 * If isValid == true, then set valid to true, otherwise to false 
				 */
				schemes.add(new ResultPair(item + "://", true & isValid)); 
				schemes.add(new ResultPair(item + ";//", false)); 
				schemes.add(new ResultPair(item + "//", false)); 
				schemes.add(new ResultPair(item + ":/", false)); 
			}
		}
		
	}

	
	protected void setUpAuthorities() {
		/* Temporary List; will be assigned to 'authorities' at end of function */
		List<ResultPair> tempAuthorities = new ArrayList<ResultPair>();

		/* Append each TLD to each authority */
		for(int i = 0; i < tldNames.length; i++) {
			ResultPair tld = tldNames[i];
			for(ResultPair auth : authorities) {
				tempAuthorities.add(new ResultPair(auth.item + '.' + tld.item, tld.valid));
			}
		}

		/* 
		 * Create various sorts of invalid authorities,
		 * and also add the contents of 'authorities' 
		 * to 'tempAuthorities' 
		 */
		for(ResultPair auth: authorities) {
			tempAuthorities.add(auth);
			tempAuthorities.add(new ResultPair('.' + auth.item, false));
		}
		
		tempAuthorities.add(new ResultPair("", false));
		tempAuthorities.add(new ResultPair(" ", false));

		/* Replace authorities with tempAuthorities */
		authorities = tempAuthorities;
	}

	@Test
	public void testAllow2Slashes() {
		UrlValidator uv = new UrlValidator(UrlValidator.ALLOW_2_SLASHES);
		assertTrue("Double slashes should be allowed", uv.isValid("http://fake.com//home"));
	}

	@Test
	public void testAllowAllSchemes() {
		UrlValidator uvAll = new UrlValidator(UrlValidator.ALLOW_ALL_SCHEMES);
		UrlValidator uvRestricted = new UrlValidator();
		
		/* Add other schemes to 'schemes' list */
		setUpSchemes(otherSchemeNames);

		for(ResultPair scheme : schemes) {
			if(scheme.valid) {
				String item = scheme.item;

				/* Test the validator that does not restrict by scheme. */
				assertTrue(String.format("Scheme '%s' should be allowed in url %s", item, item + "abc.com"), 
						uvAll.isValid(item + "abc.com"));

				/*
				 * Test the validator that restricts by scheme.
				 * http, https, and ftp schemes should be accepted;
				 * others should be rejected.
				 */
				if(item.matches("(http|https|ftp)://")) {
					assertTrue(String.format("Scheme '%s' should be allowed in url %s", item, item + "abc.com"), 
							uvRestricted.isValid(item + "abc.com"));
				} else {
					assertFalse(String.format("Scheme '%s' should be rejected in url %s", item, item + "abc.com"), 
							uvRestricted.isValid(item + "abc.com"));
				}
			}
		}
	}
	
	@Test
	public void testNoFragments() {
		UrlValidator uvNoFrag = new UrlValidator(UrlValidator.NO_FRAGMENTS);
		UrlValidator uvAllowFrag = new UrlValidator();
		String url1 = "http://www.fakeurl.com/#resource";
		String url2 = "http://www.fakeurl.com/subdir/#resource";
		assertFalse("Fragment should be rejected", uvNoFrag.isValid(url1));
		assertFalse("Fragment should be rejected", uvNoFrag.isValid(url2));
		assertTrue("Fragment should be accepted", uvAllowFrag.isValid(url1));
		assertTrue("Fragment should be accepted", uvAllowFrag.isValid(url2));
	}
	
	/*
	 * These are example valid URIs from RFC 3986
	 */
	@Test
	public void testRFC3986() {
		UrlValidator uv= new UrlValidator();

		ResultPair[] urls = {
				new ResultPair("ftp://ftp.is.co.za/rfc/rfc1808.txt", true),
				new ResultPair("http://www.ietf.org/rfc/rfc2396.txt", true),
				new ResultPair("ldap://[2001:db8::7]/c=GB?objectClass?one", true),
				new ResultPair("mailto:John.Doe@example.com", true),
				new ResultPair("news:comp.infosystems.www.servers.unix", true),
				new ResultPair("tel:+1-816-555-1212", true),
				new ResultPair("telnet://192.0.2.16:80/", true),
				new ResultPair("urn:oasis:names:specification:docbook:dtd:xml:4.1.2", true),
		};
		
		for(ResultPair url : urls) {
			assertTrue(String.format("Example URL '%s' from RFC 3986 is valid", url.item), uv.isValid(url.item));
		}
	}
	
	@Test
	public void testReservedChars() {
		UrlValidator uv= new UrlValidator();
		String url = "http://google.com";
		//assertFalse("No asterisk allowed in path", uv.isValid(url + "/*/"));
		//assertFalse("No asterisk allowed in path", uv.isValid(url + "/*"));
		//assertFalse("No percent sign allowed in path", uv.isValid(url + "/%/"));
		//assertFalse("No percent sign allowed in path", uv.isValid(url + "/%"));
		assertFalse("No question mark allowed in path", uv.isValid(url + "/?/"));
		assertFalse("No question mark allowed in path", uv.isValid(url + "/?"));
		assertFalse("No space allowed in path", uv.isValid(url + "/ /"));
		//assertFalse("No exclamation point allowed in path", uv.isValid(url + "/!/"));
		//assertFalse("No exclamation point allowed in path", uv.isValid(url + "/!"));
	}

	@Test
	public void testBed() {
		UrlValidator uv = new UrlValidator();
		/*
		 * Just a handy place for scratch work with unit tests
		 */
	}
	
	@Test
	public void testIsValid() {
		UrlValidator uv = new UrlValidator();

		for(ResultPair scheme : schemes) {
			for(ResultPair auth : authorities) {
				for(ResultPair port : ports) {
					for(ResultPair path : paths) {
						for(ResultPair query : queries) {
							String url = scheme.item + auth.item + port.item + path.item + query.item;
							Boolean valid = true;
							valid &= scheme.valid & auth.valid & port.valid & path.valid & query.valid;

							String validStr = valid ? "valid" : "invalid";
							assertTrue(String.format("URL '%s' should be %s", url, validStr), uv.isValid(url) == valid);
						}
					}
					
				}
			}
		}
	}

	/*
	 * List containing ResultPairs for URL schemes.
	 * Initialized by setUpSchemes().
	 */
	List<ResultPair> schemes = new ArrayList<ResultPair>();

	/* 
	 * CSV file containing these schemes available at:
	 * http://www.iana.org/assignments/uri-schemes/uri-schemes-1.csv
	 */
	
	ResultPair[] coreSchemeNames = {
			new ResultPair("ftp", true),
			new ResultPair("http", true),
			new ResultPair("https", true),
	};
	
	ResultPair[] otherSchemeNames = {
			/* Valid schemes */
			new ResultPair("aaa", true),
			new ResultPair("aaas", true),
			new ResultPair("about", true),
			new ResultPair("acap", true),
			new ResultPair("acct", true),
			new ResultPair("cap", true),
			new ResultPair("cid", true),
			new ResultPair("coap", true),
			new ResultPair("coaps", true),
			new ResultPair("crid", true),
			new ResultPair("data", true),
			new ResultPair("dav", true),
			new ResultPair("dict", true),
			new ResultPair("dns", true),
			new ResultPair("file", true),
			new ResultPair("geo", true),
			new ResultPair("go", true),
			new ResultPair("gopher", true),
			new ResultPair("h323", true),
			new ResultPair("iax", true),
			new ResultPair("icap", true),
			new ResultPair("im", true),
			new ResultPair("imap", true),
			new ResultPair("info", true),
			new ResultPair("ipp", true),
			new ResultPair("iris", true),
			new ResultPair("iris.beep", true),
			new ResultPair("iris.xpc", true),
			new ResultPair("iris.xpcs", true),
			new ResultPair("iris.lwz", true),
			new ResultPair("jabber", true),
			new ResultPair("ldap", true),
			new ResultPair("mailto", true),
			new ResultPair("mid", true),
			new ResultPair("msrp", true),
			new ResultPair("msrps", true),
			new ResultPair("mtqp", true),
			new ResultPair("mupdate", true),
			new ResultPair("news", true),
			new ResultPair("nfs", true),
			new ResultPair("ni", true),
			new ResultPair("nih", true),
			new ResultPair("nntp", true),
			new ResultPair("opaquelocktoken", true),
			new ResultPair("pop", true),
			new ResultPair("pres", true),
			new ResultPair("reload", true),
			new ResultPair("rtsp", true),
			new ResultPair("rtsps", true),
			new ResultPair("rtspu", true),
			new ResultPair("service", true),
			new ResultPair("session", true),
			new ResultPair("shttp", true),
			new ResultPair("sieve", true),
			new ResultPair("sip", true),
			new ResultPair("sips", true),
			new ResultPair("sms", true),
			new ResultPair("snmp", true),
			new ResultPair("soap.beep", true),
			new ResultPair("soap.beeps", true),
			new ResultPair("stun", true),
			new ResultPair("stuns", true),
			new ResultPair("tag", true),
			new ResultPair("tel", true),
			new ResultPair("telnet", true),
			new ResultPair("tftp", true),
			new ResultPair("thismessage", true),
			new ResultPair("tn3270", true),
			new ResultPair("tip", true),
			new ResultPair("turn", true),
			new ResultPair("turns", true),
			new ResultPair("tv", true),
			new ResultPair("urn", true),
			new ResultPair("vemmi", true),
			new ResultPair("ws", true),
			new ResultPair("wss", true),
			new ResultPair("xcon", true),
			new ResultPair("xcon-userid", true),
			new ResultPair("xmlrpc.beep", true),
			new ResultPair("xmlrpc.beeps", true),
			new ResultPair("xmpp", true),
			new ResultPair("z39.50r", true),
			new ResultPair("z39.50s", true),
	};
	
	ResultPair[] invalidSchemeNames = {
			new ResultPair("w3m", false),
			new ResultPair("htp", false),
			new ResultPair("shttp", false),
	};

	/* Base authorities List */
	List<ResultPair> authorities = new ArrayList<ResultPair>(Arrays.asList(
			new ResultPair("1.2.3", false),
			new ResultPair("1.2.3.4", true),
			new ResultPair("1.2.3.4.5", false),
			new ResultPair("0.0.0.0", true),
			new ResultPair("0.0.0.0.0", false),
			new ResultPair("255.255.255.255", true),
			new ResultPair("256.256.256.256", false),
			new ResultPair("google", false),
			new ResultPair("g00gle", false)
	));

	/* 
	 * Array containing these TLDs available at:
	 * http://data.iana.org/TLD/tlds-alpha-by-domain.txt
	 */
	ResultPair[] tldNames = {
			/*
			new ResultPair("ac", true),
			new ResultPair("academy", true),
			new ResultPair("accountants", true),
			new ResultPair("actor", true),
			new ResultPair("ad", true),
			new ResultPair("ae", true),
			new ResultPair("aero", true),
			new ResultPair("af", true),
			new ResultPair("ag", true),
			new ResultPair("agency", true),
			new ResultPair("ai", true),
			new ResultPair("airforce", true),
			new ResultPair("al", true),
			new ResultPair("am", true),
			new ResultPair("an", true),
			new ResultPair("ao", true),
			new ResultPair("aq", true),
			new ResultPair("ar", true),
			new ResultPair("archi", true),
			new ResultPair("arpa", true),
			new ResultPair("as", true),
			new ResultPair("asia", true),
			new ResultPair("associates", true),
			new ResultPair("at", true),
			new ResultPair("attorney", true),
			new ResultPair("au", true),
			new ResultPair("audio", true),
			new ResultPair("autos", true),
			new ResultPair("aw", true),
			new ResultPair("ax", true),
			new ResultPair("axa", true),
			new ResultPair("az", true),
			new ResultPair("ba", true),
			new ResultPair("bar", true),
			new ResultPair("bargains", true),
			new ResultPair("bayern", true),
			new ResultPair("bb", true),
			new ResultPair("bd", true),
			new ResultPair("be", true),
			new ResultPair("beer", true),
			new ResultPair("berlin", true),
			new ResultPair("best", true),
			new ResultPair("bf", true),
			new ResultPair("bg", true),
			new ResultPair("bh", true),
			new ResultPair("bi", true),
			new ResultPair("bid", true),
			new ResultPair("bike", true),
			new ResultPair("bio", true),
			new ResultPair("biz", true),
			new ResultPair("bj", true),
			new ResultPair("black", true),
			new ResultPair("blackfriday", true),
			new ResultPair("blue", true),
			new ResultPair("bm", true),
			new ResultPair("bn", true),
			new ResultPair("bo", true),
			new ResultPair("boutique", true),
			new ResultPair("br", true),
			new ResultPair("bs", true),
			new ResultPair("bt", true),
			new ResultPair("build", true),
			new ResultPair("builders", true),
			new ResultPair("buzz", true),
			new ResultPair("bv", true),
			new ResultPair("bw", true),
			new ResultPair("by", true),
			new ResultPair("bz", true),
			new ResultPair("ca", true),
			new ResultPair("cab", true),
			new ResultPair("camera", true),
			new ResultPair("camp", true),
			new ResultPair("capital", true),
			new ResultPair("cards", true),
			new ResultPair("care", true),
			new ResultPair("career", true),
			new ResultPair("careers", true),
			new ResultPair("cash", true),
			new ResultPair("cat", true),
			new ResultPair("catering", true),
			new ResultPair("cc", true),
			new ResultPair("cd", true),
			new ResultPair("center", true),
			new ResultPair("ceo", true),
			new ResultPair("cf", true),
			new ResultPair("cg", true),
			new ResultPair("ch", true),
			new ResultPair("cheap", true),
			new ResultPair("christmas", true),
			new ResultPair("church", true),
			new ResultPair("ci", true),
			new ResultPair("citic", true),
			new ResultPair("ck", true),
			new ResultPair("cl", true),
			new ResultPair("claims", true),
			new ResultPair("cleaning", true),
			new ResultPair("clinic", true),
			new ResultPair("clothing", true),
			new ResultPair("club", true),
			new ResultPair("cm", true),
			new ResultPair("cn", true),
			*/
			new ResultPair("co", true),
			new ResultPair("codes", true),
			new ResultPair("coffee", true),
			new ResultPair("college", true),
			new ResultPair("cologne", true),
			new ResultPair("com", true),
			new ResultPair("community", true),
			new ResultPair("company", true),
			new ResultPair("computer", true),
			new ResultPair("condos", true),
			new ResultPair("construction", true),
			new ResultPair("consulting", true),
			new ResultPair("contractors", true),
			new ResultPair("cooking", true),
			new ResultPair("cool", true),
			new ResultPair("coop", true),
			new ResultPair("country", true),
			new ResultPair("cr", true),
			new ResultPair("credit", true),
			new ResultPair("creditcard", true),
			new ResultPair("cruises", true),
			new ResultPair("cu", true),
			new ResultPair("cv", true),
			new ResultPair("cw", true),
			new ResultPair("cx", true),
			new ResultPair("cy", true),
			new ResultPair("cz", true),
			/*
			new ResultPair("dance", true),
			new ResultPair("dating", true),
			new ResultPair("de", true),
			new ResultPair("degree", true),
			new ResultPair("democrat", true),
			new ResultPair("dental", true),
			new ResultPair("dentist", true),
			new ResultPair("desi", true),
			new ResultPair("diamonds", true),
			new ResultPair("digital", true),
			new ResultPair("directory", true),
			new ResultPair("discount", true),
			new ResultPair("dj", true),
			new ResultPair("dk", true),
			new ResultPair("dm", true),
			new ResultPair("dnp", true),
			new ResultPair("do", true),
			new ResultPair("domains", true),
			new ResultPair("dz", true),
			new ResultPair("ec", true),
			new ResultPair("edu", true),
			new ResultPair("education", true),
			new ResultPair("ee", true),
			new ResultPair("eg", true),
			new ResultPair("email", true),
			new ResultPair("engineering", true),
			new ResultPair("enterprises", true),
			new ResultPair("equipment", true),
			new ResultPair("er", true),
			new ResultPair("es", true),
			new ResultPair("estate", true),
			new ResultPair("et", true),
			new ResultPair("eu", true),
			new ResultPair("eus", true),
			new ResultPair("events", true),
			new ResultPair("exchange", true),
			new ResultPair("expert", true),
			new ResultPair("exposed", true),
			new ResultPair("fail", true),
			new ResultPair("farm", true),
			new ResultPair("feedback", true),
			new ResultPair("fi", true),
			new ResultPair("finance", true),
			new ResultPair("financial", true),
			new ResultPair("fish", true),
			new ResultPair("fishing", true),
			new ResultPair("fitness", true),
			new ResultPair("fj", true),
			new ResultPair("fk", true),
			new ResultPair("flights", true),
			new ResultPair("florist", true),
			new ResultPair("fm", true),
			new ResultPair("fo", true),
			new ResultPair("foo", true),
			new ResultPair("foundation", true),
			new ResultPair("fr", true),
			new ResultPair("frogans", true),
			new ResultPair("fund", true),
			new ResultPair("furniture", true),
			new ResultPair("futbol", true),
			new ResultPair("ga", true),
			new ResultPair("gal", true),
			new ResultPair("gallery", true),
			new ResultPair("gb", true),
			new ResultPair("gd", true),
			new ResultPair("ge", true),
			new ResultPair("gf", true),
			new ResultPair("gg", true),
			new ResultPair("gh", true),
			new ResultPair("gi", true),
			new ResultPair("gift", true),
			new ResultPair("gl", true),
			new ResultPair("glass", true),
			new ResultPair("globo", true),
			new ResultPair("gm", true),
			new ResultPair("gmo", true),
			new ResultPair("gn", true),
			new ResultPair("gop", true),
			new ResultPair("gov", true),
			new ResultPair("gp", true),
			new ResultPair("gq", true),
			new ResultPair("gr", true),
			new ResultPair("graphics", true),
			new ResultPair("gratis", true),
			new ResultPair("gripe", true),
			new ResultPair("gs", true),
			new ResultPair("gt", true),
			new ResultPair("gu", true),
			new ResultPair("guide", true),
			new ResultPair("guitars", true),
			new ResultPair("guru", true),
			new ResultPair("gw", true),
			new ResultPair("gy", true),
			new ResultPair("haus", true),
			new ResultPair("hiphop", true),
			new ResultPair("hiv", true),
			new ResultPair("hk", true),
			new ResultPair("hm", true),
			new ResultPair("hn", true),
			new ResultPair("holdings", true),
			new ResultPair("holiday", true),
			new ResultPair("homes", true),
			new ResultPair("horse", true),
			new ResultPair("host", true),
			new ResultPair("house", true),
			new ResultPair("hr", true),
			new ResultPair("ht", true),
			new ResultPair("hu", true),
			new ResultPair("id", true),
			new ResultPair("ie", true),
			new ResultPair("il", true),
			new ResultPair("im", true),
			new ResultPair("immobilien", true),
			new ResultPair("in", true),
			new ResultPair("industries", true),
			new ResultPair("info", true),
			new ResultPair("ink", true),
			new ResultPair("institute", true),
			new ResultPair("insure", true),
			new ResultPair("int", true),
			new ResultPair("international", true),
			new ResultPair("investments", true),
			new ResultPair("io", true),
			new ResultPair("iq", true),
			new ResultPair("ir", true),
			new ResultPair("is", true),
			new ResultPair("it", true),
			new ResultPair("je", true),
			new ResultPair("jetzt", true),
			new ResultPair("jm", true),
			new ResultPair("jo", true),
			new ResultPair("jobs", true),
			new ResultPair("jp", true),
			new ResultPair("juegos", true),
			new ResultPair("kaufen", true),
			new ResultPair("ke", true),
			new ResultPair("kg", true),
			new ResultPair("kh", true),
			new ResultPair("ki", true),
			new ResultPair("kim", true),
			new ResultPair("kitchen", true),
			new ResultPair("kiwi", true),
			new ResultPair("km", true),
			new ResultPair("kn", true),
			new ResultPair("koeln", true),
			new ResultPair("kp", true),
			new ResultPair("kr", true),
			new ResultPair("kred", true),
			new ResultPair("kw", true),
			new ResultPair("ky", true),
			new ResultPair("kz", true),
			new ResultPair("la", true),
			new ResultPair("land", true),
			new ResultPair("lawyer", true),
			new ResultPair("lb", true),
			new ResultPair("lc", true),
			new ResultPair("lease", true),
			new ResultPair("li", true),
			new ResultPair("life", true),
			new ResultPair("lighting", true),
			new ResultPair("limited", true),
			new ResultPair("limo", true),
			new ResultPair("link", true),
			new ResultPair("lk", true),
			new ResultPair("loans", true),
			new ResultPair("london", true),
			new ResultPair("lr", true),
			new ResultPair("ls", true),
			new ResultPair("lt", true),
			new ResultPair("lu", true),
			new ResultPair("luxe", true),
			new ResultPair("luxury", true),
			new ResultPair("lv", true),
			new ResultPair("ly", true),
			new ResultPair("ma", true),
			new ResultPair("maison", true),
			new ResultPair("management", true),
			new ResultPair("mango", true),
			new ResultPair("market", true),
			new ResultPair("marketing", true),
			new ResultPair("mc", true),
			new ResultPair("md", true),
			new ResultPair("me", true),
			new ResultPair("media", true),
			new ResultPair("meet", true),
			new ResultPair("menu", true),
			new ResultPair("mg", true),
			new ResultPair("mh", true),
			new ResultPair("miami", true),
			new ResultPair("mil", true),
			new ResultPair("mk", true),
			new ResultPair("ml", true),
			new ResultPair("mm", true),
			new ResultPair("mn", true),
			new ResultPair("mo", true),
			new ResultPair("mobi", true),
			new ResultPair("moda", true),
			new ResultPair("moe", true),
			new ResultPair("monash", true),
			new ResultPair("mortgage", true),
			new ResultPair("moscow", true),
			new ResultPair("motorcycles", true),
			new ResultPair("mp", true),
			new ResultPair("mq", true),
			new ResultPair("mr", true),
			new ResultPair("ms", true),
			new ResultPair("mt", true),
			new ResultPair("mu", true),
			new ResultPair("museum", true),
			new ResultPair("mv", true),
			new ResultPair("mw", true),
			new ResultPair("mx", true),
			new ResultPair("my", true),
			new ResultPair("mz", true),
			new ResultPair("na", true),
			new ResultPair("nagoya", true),
			new ResultPair("name", true),
			new ResultPair("nc", true),
			new ResultPair("ne", true),
			new ResultPair("net", true),
			new ResultPair("neustar", true),
			new ResultPair("nf", true),
			new ResultPair("ng", true),
			new ResultPair("ni", true),
			new ResultPair("ninja", true),
			new ResultPair("nl", true),
			new ResultPair("no", true),
			new ResultPair("np", true),
			new ResultPair("nr", true),
			new ResultPair("nu", true),
			new ResultPair("nyc", true),
			new ResultPair("nz", true),
			new ResultPair("okinawa", true),
			new ResultPair("om", true),
			new ResultPair("onl", true),
			new ResultPair("org", true),
			new ResultPair("pa", true),
			new ResultPair("paris", true),
			new ResultPair("partners", true),
			new ResultPair("parts", true),
			new ResultPair("pe", true),
			new ResultPair("pf", true),
			new ResultPair("pg", true),
			new ResultPair("ph", true),
			new ResultPair("photo", true),
			new ResultPair("photography", true),
			new ResultPair("photos", true),
			new ResultPair("pics", true),
			new ResultPair("pictures", true),
			new ResultPair("pink", true),
			new ResultPair("pk", true),
			new ResultPair("pl", true),
			new ResultPair("plumbing", true),
			new ResultPair("pm", true),
			new ResultPair("pn", true),
			new ResultPair("post", true),
			new ResultPair("pr", true),
			new ResultPair("press", true),
			new ResultPair("pro", true),
			new ResultPair("productions", true),
			new ResultPair("properties", true),
			new ResultPair("ps", true),
			new ResultPair("pt", true),
			new ResultPair("pub", true),
			new ResultPair("pw", true),
			new ResultPair("py", true),
			new ResultPair("qa", true),
			new ResultPair("qpon", true),
			new ResultPair("quebec", true),
			new ResultPair("re", true),
			new ResultPair("recipes", true),
			new ResultPair("red", true),
			new ResultPair("reise", true),
			new ResultPair("reisen", true),
			new ResultPair("ren", true),
			new ResultPair("rentals", true),
			new ResultPair("repair", true),
			new ResultPair("report", true),
			new ResultPair("rest", true),
			new ResultPair("reviews", true),
			new ResultPair("rich", true),
			new ResultPair("rio", true),
			new ResultPair("ro", true),
			new ResultPair("rocks", true),
			new ResultPair("rodeo", true),
			new ResultPair("rs", true),
			new ResultPair("ru", true),
			new ResultPair("ruhr", true),
			new ResultPair("rw", true),
			new ResultPair("ryukyu", true),
			new ResultPair("sa", true),
			new ResultPair("saarland", true),
			new ResultPair("sb", true),
			new ResultPair("sc", true),
			new ResultPair("schule", true),
			new ResultPair("sd", true),
			new ResultPair("se", true),
			new ResultPair("services", true),
			new ResultPair("sexy", true),
			new ResultPair("sg", true),
			new ResultPair("sh", true),
			new ResultPair("shiksha", true),
			new ResultPair("shoes", true),
			new ResultPair("si", true),
			new ResultPair("singles", true),
			new ResultPair("sj", true),
			new ResultPair("sk", true),
			new ResultPair("sl", true),
			new ResultPair("sm", true),
			new ResultPair("sn", true),
			new ResultPair("so", true),
			new ResultPair("social", true),
			new ResultPair("software", true),
			new ResultPair("sohu", true),
			new ResultPair("solar", true),
			new ResultPair("solutions", true),
			new ResultPair("soy", true),
			new ResultPair("space", true),
			new ResultPair("sr", true),
			new ResultPair("st", true),
			new ResultPair("su", true),
			new ResultPair("supplies", true),
			new ResultPair("supply", true),
			new ResultPair("support", true),
			new ResultPair("surgery", true),
			new ResultPair("sv", true),
			new ResultPair("sx", true),
			new ResultPair("sy", true),
			new ResultPair("systems", true),
			new ResultPair("sz", true),
			new ResultPair("tattoo", true),
			new ResultPair("tax", true),
			new ResultPair("tc", true),
			new ResultPair("td", true),
			new ResultPair("technology", true),
			new ResultPair("tel", true),
			new ResultPair("tf", true),
			new ResultPair("tg", true),
			new ResultPair("th", true),
			new ResultPair("tienda", true),
			new ResultPair("tips", true),
			new ResultPair("tj", true),
			new ResultPair("tk", true),
			new ResultPair("tl", true),
			new ResultPair("tm", true),
			new ResultPair("tn", true),
			new ResultPair("to", true),
			new ResultPair("today", true),
			new ResultPair("tokyo", true),
			new ResultPair("tools", true),
			new ResultPair("town", true),
			new ResultPair("toys", true),
			new ResultPair("tp", true),
			new ResultPair("tr", true),
			new ResultPair("trade", true),
			new ResultPair("training", true),
			new ResultPair("travel", true),
			new ResultPair("tt", true),
			new ResultPair("tv", true),
			new ResultPair("tw", true),
			new ResultPair("tz", true),
			new ResultPair("ua", true),
			new ResultPair("ug", true),
			new ResultPair("uk", true),
			new ResultPair("university", true),
			new ResultPair("uno", true),
			new ResultPair("us", true),
			new ResultPair("uy", true),
			new ResultPair("uz", true),
			new ResultPair("va", true),
			new ResultPair("vacations", true),
			new ResultPair("vc", true),
			new ResultPair("ve", true),
			new ResultPair("vegas", true),
			new ResultPair("ventures", true),
			new ResultPair("versicherung", true),
			new ResultPair("vet", true),
			new ResultPair("vg", true),
			new ResultPair("vi", true),
			new ResultPair("viajes", true),
			new ResultPair("villas", true),
			new ResultPair("vision", true),
			new ResultPair("vn", true),
			new ResultPair("vodka", true),
			new ResultPair("vote", true),
			new ResultPair("voting", true),
			new ResultPair("voto", true),
			new ResultPair("voyage", true),
			new ResultPair("vu", true),
			new ResultPair("wang", true),
			new ResultPair("watch", true),
			new ResultPair("webcam", true),
			new ResultPair("website", true),
			new ResultPair("wed", true),
			new ResultPair("wf", true),
			new ResultPair("wien", true),
			new ResultPair("wiki", true),
			new ResultPair("works", true),
			new ResultPair("ws", true),
			new ResultPair("wtc", true),
			new ResultPair("wtf", true),
			new ResultPair("xn--3bst00m", true),
			new ResultPair("xn--3ds443g", true),
			new ResultPair("xn--3e0b707e", true),
			new ResultPair("xn--45brj9c", true),
			new ResultPair("xn--4gbrim", true),
			new ResultPair("xn--55qw42g", true),
			new ResultPair("xn--55qx5d", true),
			new ResultPair("xn--6frz82g", true),
			new ResultPair("xn--6qq986b3xl", true),
			new ResultPair("xn--80adxhks", true),
			new ResultPair("xn--80ao21a", true),
			new ResultPair("xn--80asehdb", true),
			new ResultPair("xn--80aswg", true),
			new ResultPair("xn--90a3ac", true),
			new ResultPair("xn--c1avg", true),
			new ResultPair("xn--cg4bki", true),
			new ResultPair("xn--clchc0ea0b2g2a9gcd", true),
			new ResultPair("xn--czr694b", true),
			new ResultPair("xn--czru2d", true),
			new ResultPair("xn--d1acj3b", true),
			new ResultPair("xn--fiq228c5hs", true),
			new ResultPair("xn--fiq64b", true),
			new ResultPair("xn--fiqs8s", true),
			new ResultPair("xn--fiqz9s", true),
			new ResultPair("xn--fpcrj9c3d", true),
			new ResultPair("xn--fzc2c9e2c", true),
			new ResultPair("xn--gecrj9c", true),
			new ResultPair("xn--h2brj9c", true),
			new ResultPair("xn--i1b6b1a6a2e", true),
			new ResultPair("xn--io0a7i", true),
			new ResultPair("xn--j1amh", true),
			new ResultPair("xn--j6w193g", true),
			new ResultPair("xn--kprw13d", true),
			new ResultPair("xn--kpry57d", true),
			new ResultPair("xn--l1acc", true),
			new ResultPair("xn--lgbbat1ad8j", true),
			new ResultPair("xn--mgb9awbf", true),
			new ResultPair("xn--mgba3a4f16a", true),
			new ResultPair("xn--mgbaam7a8h", true),
			new ResultPair("xn--mgbab2bd", true),
			new ResultPair("xn--mgbayh7gpa", true),
			new ResultPair("xn--mgbbh1a71e", true),
			new ResultPair("xn--mgbc0a9azcg", true),
			new ResultPair("xn--mgberp4a5d4ar", true),
			new ResultPair("xn--mgbx4cd0ab", true),
			new ResultPair("xn--ngbc5azd", true),
			new ResultPair("xn--nqv7f", true),
			new ResultPair("xn--nqv7fs00ema", true),
			new ResultPair("xn--o3cw4h", true),
			new ResultPair("xn--ogbpf8fl", true),
			new ResultPair("xn--p1ai", true),
			new ResultPair("xn--pgbs0dh", true),
			new ResultPair("xn--q9jyb4c", true),
			new ResultPair("xn--rhqv96g", true),
			new ResultPair("xn--s9brj9c", true),
			new ResultPair("xn--ses554g", true),
			new ResultPair("xn--unup4y", true),
			new ResultPair("xn--wgbh1c", true),
			new ResultPair("xn--wgbl6a", true),
			new ResultPair("xn--xkc2al3hye2a", true),
			new ResultPair("xn--xkc2dl3a5ee0h", true),
			new ResultPair("xn--yfro4i67o", true),
			new ResultPair("xn--ygbi2ammx", true),
			new ResultPair("xn--zfr164b", true),
			new ResultPair("xxx", true),
			new ResultPair("xyz", true),
			new ResultPair("yachts", true),
			new ResultPair("ye", true),
			new ResultPair("yokohama", true),
			new ResultPair("yt", true),
			new ResultPair("za", true),
			new ResultPair("zm", true),
			new ResultPair("zone", true),
			new ResultPair("zw", true),
			*/
			
			/* Invalid TLDs */

			/* 
			 * No numbers or special characters allowed, other than
			 * as defined above 
			 * */
			new ResultPair("111", false),
			new ResultPair("b@d", false),
			new ResultPair("w3m", false),

			/* No spaces allowed */
			new ResultPair(" ", false),
			
	};
	
	List<ResultPair> ports = new ArrayList<ResultPair>(Arrays.asList(
			/* Valid ports defined by IANA */
			new ResultPair("", true),
			new ResultPair(":0", true),
			new ResultPair(":80", true),
			new ResultPair(":1024", true),
			new ResultPair(":49151", true),
			new ResultPair(":65535", true),
			new ResultPair(":1", true),
			new ResultPair(":11", true),
			new ResultPair(":111", true),
			new ResultPair(":1111", true),
			new ResultPair(":11111", true),
			new ResultPair(":111111", false),

			/* Ports with invalid extra characters */
			new ResultPair(":", false),
			new ResultPair("::80", false),
			new ResultPair(":80:80", false),
			
			/* Ports with letters */
			new ResultPair(":a", false),
			new ResultPair(":bad", false),
			new ResultPair(":3p0", false),
			new ResultPair(":3X1T", false),
			new ResultPair(":8OO8S", false),

			/* Ports in invalid ranges */
			new ResultPair(":-1", false)
			/* 
			 * The maximum defined port is 65535; see:
			 * https://www.iana.org/assignments/service-names-port-numbers/service-names-port-numbers.xhtml
			 * 
			 * However, 65536 passes the check.
			 */
			//new ResultPair(":65536", false)
	));
	
	List<ResultPair> paths = new ArrayList<ResultPair>(Arrays.asList(
			new ResultPair("/..", false),
			/*
			new ResultPair("/.", true),
			*/
			new ResultPair("/ /", false),
			new ResultPair("/fake/path", true),
			new ResultPair("/fake//path", false),
			new ResultPair("/a12", true),
			new ResultPair("/123", true),
			new ResultPair("/$12", true),
			/* For some reason, these characters appear to be valid even though they are reserved */
			//new ResultPair("/*/", false),
			//new ResultPair("/?/", false),
			//new ResultPair("/%/", false),
			new ResultPair("/", true),
			new ResultPair("", true)
    ));
	
	List<ResultPair> queries = new ArrayList<ResultPair>(Arrays.asList(
			new ResultPair("", true),
			new ResultPair("?active=true", true),
			/*
			 * See RFC 3986 - queries can be terminated either by the end of URI or by number sign
			 */
			new ResultPair("?active=true#home", true)
	));
}
